3  * Copyright 2015 gRPC authors.
 
   5  * Licensed under the Apache License, Version 2.0 (the "License");
 
   6  * you may not use this file except in compliance with the License.
 
   7  * You may obtain a copy of the License at
 
   9  *     http://www.apache.org/licenses/LICENSE-2.0
 
  11  * Unless required by applicable law or agreed to in writing, software
 
  12  * distributed under the License is distributed on an "AS IS" BASIS,
 
  13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  * See the License for the specific language governing permissions and
 
  15  * limitations under the License.
 
  19 #include <grpc/support/port_platform.h>
 
  27 #include <grpc/support/alloc.h>
 
  28 #include <grpc/support/string_util.h>
 
  30 #include <address_sorting/address_sorting.h>
 
  32 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
 
  33 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 
  34 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 
  35 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
 
  36 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 
  37 #include "src/core/ext/filters/client_channel/server_address.h"
 
  38 #include "src/core/ext/filters/client_channel/service_config.h"
 
  39 #include "src/core/lib/backoff/backoff.h"
 
  40 #include "src/core/lib/channel/channel_args.h"
 
  41 #include "src/core/lib/gpr/host_port.h"
 
  42 #include "src/core/lib/gpr/string.h"
 
  43 #include "src/core/lib/gprpp/manual_constructor.h"
 
  44 #include "src/core/lib/iomgr/combiner.h"
 
  45 #include "src/core/lib/iomgr/gethostname.h"
 
  46 #include "src/core/lib/iomgr/iomgr_custom.h"
 
  47 #include "src/core/lib/iomgr/resolve_address.h"
 
  48 #include "src/core/lib/iomgr/timer.h"
 
  49 #include "src/core/lib/json/json.h"
 
  51 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
 
  52 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
 
  53 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
 
  54 #define GRPC_DNS_RECONNECT_JITTER 0.2
 
  60 const char kDefaultPort[] = "https";
 
  62 class AresDnsResolver : public Resolver {
 
  64   explicit AresDnsResolver(ResolverArgs args);
 
  66   void StartLocked() override;
 
  68   void RequestReresolutionLocked() override;
 
  70   void ResetBackoffLocked() override;
 
  72   void ShutdownLocked() override;
 
  75   virtual ~AresDnsResolver();
 
  77   void MaybeStartResolvingLocked();
 
  78   void StartResolvingLocked();
 
  80   static void OnNextResolutionLocked(void* arg, grpc_error* error);
 
  81   static void OnResolvedLocked(void* arg, grpc_error* error);
 
  83   /// DNS server to use (if not system default)
 
  85   /// name to resolve (usually the same as target_name)
 
  86   char* name_to_resolve_;
 
  88   grpc_channel_args* channel_args_;
 
  89   /// whether to request the service config
 
  90   bool request_service_config_;
 
  91   /// pollset_set to drive the name resolution process
 
  92   grpc_pollset_set* interested_parties_;
 
  93   /// closures used by the combiner
 
  94   grpc_closure on_next_resolution_;
 
  95   grpc_closure on_resolved_;
 
  96   /// are we currently resolving?
 
  97   bool resolving_ = false;
 
  98   /// the pending resolving request
 
  99   grpc_ares_request* pending_request_ = nullptr;
 
 100   /// next resolution timer
 
 101   bool have_next_resolution_timer_ = false;
 
 102   grpc_timer next_resolution_timer_;
 
 103   /// min interval between DNS requests
 
 104   grpc_millis min_time_between_resolutions_;
 
 105   /// timestamp of last DNS request
 
 106   grpc_millis last_resolution_timestamp_ = -1;
 
 107   /// retry backoff state
 
 109   /// currently resolving addresses
 
 110   UniquePtr<ServerAddressList> addresses_;
 
 111   /// currently resolving service config
 
 112   char* service_config_json_ = nullptr;
 
 113   // has shutdown been initiated
 
 114   bool shutdown_initiated_ = false;
 
 115   // timeout in milliseconds for active DNS queries
 
 116   int query_timeout_ms_;
 
 117   // whether or not to enable SRV DNS queries
 
 118   bool enable_srv_queries_;
 
 121 AresDnsResolver::AresDnsResolver(ResolverArgs args)
 
 122     : Resolver(args.combiner, std::move(args.result_handler)),
 
 125               .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
 
 127               .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
 
 128               .set_jitter(GRPC_DNS_RECONNECT_JITTER)
 
 129               .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
 
 130   // Get name to resolve from URI path.
 
 131   const char* path = args.uri->path;
 
 132   if (path[0] == '/') ++path;
 
 133   name_to_resolve_ = gpr_strdup(path);
 
 134   // Get DNS server from URI authority.
 
 135   dns_server_ = nullptr;
 
 136   if (0 != strcmp(args.uri->authority, "")) {
 
 137     dns_server_ = gpr_strdup(args.uri->authority);
 
 139   channel_args_ = grpc_channel_args_copy(args.args);
 
 140   // Disable service config option
 
 141   const grpc_arg* arg = grpc_channel_args_find(
 
 142       channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
 
 143   request_service_config_ = !grpc_channel_arg_get_bool(arg, true);
 
 144   // Min time b/t resolutions option
 
 145   arg = grpc_channel_args_find(channel_args_,
 
 146                                GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
 
 147   min_time_between_resolutions_ =
 
 148       grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
 
 149   // Enable SRV queries option
 
 150   arg = grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ENABLE_SRV_QUERIES);
 
 151   enable_srv_queries_ = grpc_channel_arg_get_bool(arg, false);
 
 152   interested_parties_ = grpc_pollset_set_create();
 
 153   if (args.pollset_set != nullptr) {
 
 154     grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
 
 156   GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolutionLocked, this,
 
 157                     grpc_combiner_scheduler(combiner()));
 
 158   GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this,
 
 159                     grpc_combiner_scheduler(combiner()));
 
 160   const grpc_arg* query_timeout_ms_arg =
 
 161       grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
 
 162   query_timeout_ms_ = grpc_channel_arg_get_integer(
 
 163       query_timeout_ms_arg,
 
 164       {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX});
 
 167 AresDnsResolver::~AresDnsResolver() {
 
 168   GRPC_CARES_TRACE_LOG("resolver:%p destroying AresDnsResolver", this);
 
 169   grpc_pollset_set_destroy(interested_parties_);
 
 170   gpr_free(dns_server_);
 
 171   gpr_free(name_to_resolve_);
 
 172   grpc_channel_args_destroy(channel_args_);
 
 175 void AresDnsResolver::StartLocked() {
 
 176   GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::StartLocked() is called.",
 
 178   MaybeStartResolvingLocked();
 
 181 void AresDnsResolver::RequestReresolutionLocked() {
 
 183     MaybeStartResolvingLocked();
 
 187 void AresDnsResolver::ResetBackoffLocked() {
 
 188   if (have_next_resolution_timer_) {
 
 189     grpc_timer_cancel(&next_resolution_timer_);
 
 194 void AresDnsResolver::ShutdownLocked() {
 
 195   shutdown_initiated_ = true;
 
 196   if (have_next_resolution_timer_) {
 
 197     grpc_timer_cancel(&next_resolution_timer_);
 
 199   if (pending_request_ != nullptr) {
 
 200     grpc_cancel_ares_request_locked(pending_request_);
 
 204 void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
 
 205   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
 
 206   GRPC_CARES_TRACE_LOG(
 
 207       "resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: "
 
 209       r, grpc_error_string(error), r->shutdown_initiated_);
 
 210   r->have_next_resolution_timer_ = false;
 
 211   if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) {
 
 212     if (!r->resolving_) {
 
 213       GRPC_CARES_TRACE_LOG(
 
 214           "resolver:%p start resolving due to re-resolution timer", r);
 
 215       r->StartResolvingLocked();
 
 218   r->Unref(DEBUG_LOCATION, "next_resolution_timer");
 
 221 bool ValueInJsonArray(grpc_json* array, const char* value) {
 
 222   for (grpc_json* entry = array->child; entry != nullptr; entry = entry->next) {
 
 223     if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) {
 
 230 char* ChooseServiceConfig(char* service_config_choice_json,
 
 231                           grpc_error** error) {
 
 232   grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
 
 233   if (choices_json == nullptr) {
 
 234     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 235         "Service Config JSON Parsing, error: could not parse");
 
 238   if (choices_json->type != GRPC_JSON_ARRAY) {
 
 239     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 240         "Service Config Choices, error: should be of type array");
 
 243   char* service_config = nullptr;
 
 244   InlinedVector<grpc_error*, 4> error_list;
 
 245   bool found_choice = false;  // have we found a choice?
 
 246   for (grpc_json* choice = choices_json->child; choice != nullptr;
 
 247        choice = choice->next) {
 
 248     if (choice->type != GRPC_JSON_OBJECT) {
 
 249       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 250           "Service Config Choice, error: should be of type object"));
 
 253     grpc_json* service_config_json = nullptr;
 
 254     bool selected = true;  // has this choice been rejected?
 
 255     for (grpc_json* field = choice->child; field != nullptr;
 
 256          field = field->next) {
 
 257       // Check client language, if specified.
 
 258       if (strcmp(field->key, "clientLanguage") == 0) {
 
 259         if (field->type != GRPC_JSON_ARRAY) {
 
 260           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 261               "field:clientLanguage error:should be of type array"));
 
 262         } else if (!ValueInJsonArray(field, "c++")) {
 
 266       // Check client hostname, if specified.
 
 267       if (strcmp(field->key, "clientHostname") == 0) {
 
 268         if (field->type != GRPC_JSON_ARRAY) {
 
 269           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 270               "field:clientHostname error:should be of type array"));
 
 273         char* hostname = grpc_gethostname();
 
 274         if (hostname == nullptr || !ValueInJsonArray(field, hostname)) {
 
 278       // Check percentage, if specified.
 
 279       if (strcmp(field->key, "percentage") == 0) {
 
 280         if (field->type != GRPC_JSON_NUMBER) {
 
 281           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 282               "field:percentage error:should be of type number"));
 
 285         int random_pct = rand() % 100;
 
 287         if (sscanf(field->value, "%d", &percentage) != 1) {
 
 288           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 289               "field:percentage error:should be of type integer"));
 
 292         if (random_pct > percentage || percentage == 0) {
 
 296       // Save service config.
 
 297       if (strcmp(field->key, "serviceConfig") == 0) {
 
 298         if (field->type == GRPC_JSON_OBJECT) {
 
 299           service_config_json = field;
 
 301           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 302               "field:serviceConfig error:should be of type object"));
 
 306     if (!found_choice && selected && service_config_json != nullptr) {
 
 307       service_config = grpc_json_dump_to_string(service_config_json, 0);
 
 311   grpc_json_destroy(choices_json);
 
 312   if (!error_list.empty()) {
 
 313     gpr_free(service_config);
 
 314     service_config = nullptr;
 
 315     *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser",
 
 318   return service_config;
 
 321 void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
 
 322   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
 
 323   GPR_ASSERT(r->resolving_);
 
 324   r->resolving_ = false;
 
 325   gpr_free(r->pending_request_);
 
 326   r->pending_request_ = nullptr;
 
 327   if (r->shutdown_initiated_) {
 
 328     r->Unref(DEBUG_LOCATION, "OnResolvedLocked() shutdown");
 
 331   if (r->addresses_ != nullptr) {
 
 333     result.addresses = std::move(*r->addresses_);
 
 334     if (r->service_config_json_ != nullptr) {
 
 335       char* service_config_string = ChooseServiceConfig(
 
 336           r->service_config_json_, &result.service_config_error);
 
 337       gpr_free(r->service_config_json_);
 
 338       if (result.service_config_error == GRPC_ERROR_NONE &&
 
 339           service_config_string != nullptr) {
 
 340         GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s",
 
 341                              r, service_config_string);
 
 342         result.service_config = ServiceConfig::Create(
 
 343             service_config_string, &result.service_config_error);
 
 345       gpr_free(service_config_string);
 
 347     result.args = grpc_channel_args_copy(r->channel_args_);
 
 348     r->result_handler()->ReturnResult(std::move(result));
 
 349     r->addresses_.reset();
 
 350     // Reset backoff state so that we start from the beginning when the
 
 351     // next request gets triggered.
 
 354     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", r,
 
 355                          grpc_error_string(error));
 
 356     r->result_handler()->ReturnError(grpc_error_set_int(
 
 357         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
 
 358             "DNS resolution failed", &error, 1),
 
 359         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
 
 361     grpc_millis next_try = r->backoff_.NextAttemptTime();
 
 362     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
 
 363     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s",
 
 364                          r, grpc_error_string(error));
 
 365     GPR_ASSERT(!r->have_next_resolution_timer_);
 
 366     r->have_next_resolution_timer_ = true;
 
 367     // TODO(roth): We currently deal with this ref manually.  Once the
 
 368     // new closure API is done, find a way to track this ref with the timer
 
 369     // callback as part of the type system.
 
 370     r->Ref(DEBUG_LOCATION, "retry-timer").release();
 
 372       GRPC_CARES_TRACE_LOG("resolver:%p retrying in %" PRId64 " milliseconds",
 
 375       GRPC_CARES_TRACE_LOG("resolver:%p retrying immediately", r);
 
 377     grpc_timer_init(&r->next_resolution_timer_, next_try,
 
 378                     &r->on_next_resolution_);
 
 380   r->Unref(DEBUG_LOCATION, "dns-resolving");
 
 383 void AresDnsResolver::MaybeStartResolvingLocked() {
 
 384   // If there is an existing timer, the time it fires is the earliest time we
 
 385   // can start the next resolution.
 
 386   if (have_next_resolution_timer_) return;
 
 387   if (last_resolution_timestamp_ >= 0) {
 
 388     const grpc_millis earliest_next_resolution =
 
 389         last_resolution_timestamp_ + min_time_between_resolutions_;
 
 390     const grpc_millis ms_until_next_resolution =
 
 391         earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
 
 392     if (ms_until_next_resolution > 0) {
 
 393       const grpc_millis last_resolution_ago =
 
 394           grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
 
 395       GRPC_CARES_TRACE_LOG(
 
 396           "resolver:%p In cooldown from last resolution (from %" PRId64
 
 397           " ms ago). Will resolve again in %" PRId64 " ms",
 
 398           this, last_resolution_ago, ms_until_next_resolution);
 
 399       have_next_resolution_timer_ = true;
 
 400       // TODO(roth): We currently deal with this ref manually.  Once the
 
 401       // new closure API is done, find a way to track this ref with the timer
 
 402       // callback as part of the type system.
 
 403       Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown").release();
 
 404       grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
 
 405                       &on_next_resolution_);
 
 409   StartResolvingLocked();
 
 412 void AresDnsResolver::StartResolvingLocked() {
 
 413   // TODO(roth): We currently deal with this ref manually.  Once the
 
 414   // new closure API is done, find a way to track this ref with the timer
 
 415   // callback as part of the type system.
 
 416   Ref(DEBUG_LOCATION, "dns-resolving").release();
 
 417   GPR_ASSERT(!resolving_);
 
 419   service_config_json_ = nullptr;
 
 420   pending_request_ = grpc_dns_lookup_ares_locked(
 
 421       dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
 
 422       &on_resolved_, &addresses_, enable_srv_queries_ /* check_grpclb */,
 
 423       request_service_config_ ? &service_config_json_ : nullptr,
 
 424       query_timeout_ms_, combiner());
 
 425   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
 
 426   GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. pending_request_:%p",
 
 427                        this, pending_request_);
 
 434 class AresDnsResolverFactory : public ResolverFactory {
 
 436   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
 
 437     return OrphanablePtr<Resolver>(New<AresDnsResolver>(std::move(args)));
 
 440   const char* scheme() const override { return "dns"; }
 
 445 }  // namespace grpc_core
 
 447 extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
 
 448 static grpc_address_resolver_vtable* default_resolver;
 
 450 static grpc_error* blocking_resolve_address_ares(
 
 451     const char* name, const char* default_port,
 
 452     grpc_resolved_addresses** addresses) {
 
 453   return default_resolver->blocking_resolve_address(name, default_port,
 
 457 static grpc_address_resolver_vtable ares_resolver = {
 
 458     grpc_resolve_address_ares, blocking_resolve_address_ares};
 
 461 /* TODO(murgatroid99): Remove this when we want the cares resolver to be the
 
 462  * default when using libuv */
 
 463 static bool should_use_ares(const char* resolver_env) {
 
 464   return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0;
 
 467 static bool should_use_ares(const char* resolver_env) {
 
 468   // TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support
 
 469   // custom IO managers (e.g. gevent).
 
 470   return !g_custom_iomgr_enabled &&
 
 471          (resolver_env == nullptr || strlen(resolver_env) == 0 ||
 
 472           gpr_stricmp(resolver_env, "ares") == 0);
 
 476 static bool g_use_ares_dns_resolver;
 
 478 void grpc_resolver_dns_ares_init() {
 
 479   grpc_core::UniquePtr<char> resolver =
 
 480       GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
 
 481   if (should_use_ares(resolver.get())) {
 
 482     g_use_ares_dns_resolver = true;
 
 483     gpr_log(GPR_DEBUG, "Using ares dns resolver");
 
 484     address_sorting_init();
 
 485     grpc_error* error = grpc_ares_init();
 
 486     if (error != GRPC_ERROR_NONE) {
 
 487       GRPC_LOG_IF_ERROR("grpc_ares_init() failed", error);
 
 490     if (default_resolver == nullptr) {
 
 491       default_resolver = grpc_resolve_address_impl;
 
 493     grpc_set_resolver_impl(&ares_resolver);
 
 494     grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
 
 495         grpc_core::UniquePtr<grpc_core::ResolverFactory>(
 
 496             grpc_core::New<grpc_core::AresDnsResolverFactory>()));
 
 498     g_use_ares_dns_resolver = false;
 
 502 void grpc_resolver_dns_ares_shutdown() {
 
 503   if (g_use_ares_dns_resolver) {
 
 504     address_sorting_shutdown();
 
 509 #else /* GRPC_ARES == 1 */
 
 511 void grpc_resolver_dns_ares_init(void) {}
 
 513 void grpc_resolver_dns_ares_shutdown(void) {}
 
 515 #endif /* GRPC_ARES == 1 */